use snafu::prelude::*;
use snafu::Location;
use snafu_ext::with_err_location;

use std::{fs, io, path::PathBuf};

#[with_err_location(serde = true)]
#[derive(Debug, Snafu)]
enum AppError {
    #[snafu(display("Unable to read configuration from {}", path.display()))]
    ReadConfiguration {
        source: io::Error,

        path: PathBuf,

        #[snafu(implicit)]
        location: Location,
    },

    #[snafu(display("Unable to write result to {}", path.display()))]
    WriteResult {
        source: io::Error,

        path: PathBuf,

        #[snafu(implicit)]
        location: Location,
    },

    #[snafu(display("Others error {}", info))]
    Others { info: String },
}

fn main() {
    process_data().unwrap();
}

fn process_data() -> std::result::Result<(), AppError> {
    let err = AppError::others("ni dong de".to_string());
    let path = "config.toml";
    let configuration = fs::read_to_string(path).context(ReadConfigurationSnafu { path })?;
    let path = unpack_config(&configuration);
    fs::write(&path, b"My complex calculation").context(WriteResultSnafu { path })?;
    Ok(())
}

fn unpack_config(data: &str) -> &str {
    "/some/path/that/does/not/exist"
}
